/*
    Geocache: some utilities for managing and visualizing geocache information
    Copyright (C) 2008  Gary Jackson

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/*
 * MessageToParts.java
 */

package com.thegbomb.geocache;

import com.thegbomb.common.*;
import com.thegbomb.common.Mapper;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.regex.Pattern;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import org.apache.log4j.Logger;

/**
 *
 * @author Gary Jackson
 */
public class MessageToParts implements Mapper<Message, Part> {
    static private Logger logger = Logger.getLogger(MessageToParts.class);
    private static final Pattern MULTIPART = Pattern.compile("^multipart/mixed;.*",
            Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
    private static final Pattern ANY = Pattern.compile(".*", Pattern.MULTILINE | Pattern.DOTALL);
    private Pattern pattern;
    
    /**
     * Creates a new instance of MessageToParts that will return parts where the
     * MIME-type matches the given pattern.
     */
    public MessageToParts(Pattern pattern) {
        this.pattern = pattern;
    }
    
    /**
     * Convenience constructor identical to:
     * new MessageToParts(Pattern.compile(regex))
     */
    public MessageToParts(String regex) {
        this(Pattern.compile(regex));
    }
    
    /**
     * Creates a new instance of MessageToParts that will return all leaf parts.
     */
    public MessageToParts() {
        this(ANY);
    }
    
    public Iterator<Part> map(Message input) {
        LinkedList<Part> output = new LinkedList<Part>();
        LinkedList<Part> stack = new LinkedList<Part>();
        stack.addLast(input);
        
        try {
            // Depth first traversal of the attachment tree
            while (! stack.isEmpty()) {
                Part p = stack.removeFirst();
                
                String type = p.getContentType();
                
                if (this.pattern.matcher(type).matches()) {
                    output.addLast(p);
                }
                
                if (MULTIPART.matcher(type).matches()) {
                    Multipart m = (Multipart)p.getContent();
                    int count = m.getCount();
                    
                    // Add items in reverse so they get processed in the correct order
                    for (int j = count - 1; j >= 0; j--) {
                        stack.addFirst(m.getBodyPart(j));
                    }
                }
            }
            
            return output.iterator();
        } catch (MessagingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
